package com.apes.framework.plugin.fileserver.service;

import com.alibaba.fastjson.JSON;
import com.apes.framework.jpa.ApesBean;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.event.EventConst;
import com.apes.framework.plugin.event.Listener;
import com.apes.framework.plugin.fileserver.domain.File;
import com.apes.framework.plugin.fileserver.repository.gridFs.GridFsRepository;
import com.apes.framework.plugin.fileserver.repository.mongo.FileMongoRepository;
import com.apes.framework.util.ReflectUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Service;

import javax.persistence.Entity;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * 功能：File 服务
 *
 * @author xul
 * @create 2018-05-25 14:38
 */
@Service
public class FileService {

    @Value("${fileserver.storage.type}")
    private String storageType;

    @Value("${fileserver.storage.not-allowed-repeat:true}")
    private boolean storageNotAllowedRepeat;

    @Autowired
    public FileMongoRepository fileRepository;  //Mongodb（文件大小不能超过16M）

    @Autowired
    public GridFsRepository gfsRepository;  //GridFs（文件大小不限）

    /**
     * 保存文件
     *
     * @param file
     * @return
     */
    public File saveFile(File file) {
        if (storageType.equals("GridFs")) {
            File f = null;
            if (storageNotAllowedRepeat) {
                f = gfsRepository.findFirstByMd5(file.getMd5());
            }
            if (f != null) {
                if (!f.getName().equals(file.getName())) {
                    if (gfsRepository.updateFileName(f.getId(), file.getName())) {
                        f.setName(file.getName());
                    }
                }
                return f;
            }
            return gfsRepository.save(file);
        }
        File f = null;
        if (storageNotAllowedRepeat) {
            f = fileRepository.findFirstByMd5(file.getMd5());
        }
        if (f != null) {
            if (!f.getName().equals(file.getName())) {
                f = fileRepository.save(file);
            }
            return f;
        }
        return fileRepository.save(file);
    }

    /**
     * 删除文件
     *
     * @param id
     * @return
     */
    public void removeFile(String id) {
        if (storageType.equals("GridFs")) {
            gfsRepository.delete(id);
            return;
        }
        fileRepository.deleteById(id);
    }

    /**
     * 根据id获取文件
     *
     * @param id
     * @return
     */
    public File getFileById(String id) {
        if (storageType.equals("GridFs")) {
            try {
                File file = gfsRepository.findOne(id);
                if (file != null) {
                    return file;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return fileRepository.findById(id).orElse(null);
    }

    /**
     * 分页查询，按上传时间降序
     *
     * @param pageIndex
     * @param pageSize
     * @return
     */
    public List<File> listFilesByPage(int pageIndex, int pageSize) {
        Sort sort = new Sort(Direction.DESC, "uploadDate");
        Pageable pageable = PageRequest.of(pageIndex, pageSize, sort);
        if (storageType.equals("GridFs")) {
            return gfsRepository.findAll(pageable).getContent();
        }
        return fileRepository.findAll(pageable).getContent();
    }

    /**
     * JPA实体插入后事件
     **/
    @Listener(topic = EventConst.POST_PERSIST_EVENT)
    public void postPersist(SimpleRequest request) {
        Object entity = request.getData();
        setFileStatus(entity);
    }

    /**
     * JPA实体插入后事件
     **/
    @Listener(topic = EventConst.POST_UPDATE_EVENT)
    public void postUpdate(SimpleRequest request) {
        Object entity = request.getData();
        setFileStatus(entity);
    }


    private void setFileStatus(Object entity) {
        if (entity == null) {
            return;
        }
        if (!ApesBean.class.isAssignableFrom(entity.getClass())) {
            return;
        }
        if (ReflectUtil.getAnnotation(entity.getClass(), Entity.class) == null) {
            return;
        }
        PropertyDescriptor[] propertyDescriptors = ReflectUtil.getPropertyDescriptors(entity);
        if (propertyDescriptors == null) {
            return;
        }
        for (PropertyDescriptor descriptor : propertyDescriptors) {
            com.apes.framework.plugin.fileserver.File annotation = ReflectUtil.getAnnotation(entity, descriptor.getName(), com.apes.framework.plugin.fileserver.File.class);
            if (annotation == null) {
                continue;
            }
            try {
                Method getter = descriptor.getReadMethod();
                Object value = getter != null ? getter.invoke(entity) : null;
                if (value == null || !(value instanceof String)) {
                    continue;
                }
                List rows = JSON.parseArray((String) value);
                rows.stream().forEach(row -> {
                    if (((Map) row).get("url") != null) {
                        return; // 针对外部图片链接所做修改
                    }
                    setFileStatus(((Map) row).get("id").toString(), 1);
                });
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }



    /**
     * 更新文件状态
     *
     * @param id
     * @param status
     */
    private void setFileStatus(String id, int status) {
        if (storageType.equals("GridFs")) {
            gfsRepository.updateFileStatus(id, status);
            return;
        }
        File file = fileRepository.findById(id).orElseThrow(() -> new RuntimeException("文件：" + id + " 不存在！"));
        if (file.getStatus() == status) {
            return;
        }
        file.setStatus(status);
        fileRepository.save(file);
    }
}
